﻿using Abp.AspNetCore;
using Abp.Castle.Logging.Log4Net;
using Abp.EntityFrameworkCore;
using Castle.Facilities.Logging;
using HCD.EntityFrameworkCore;
using HCD.Web.MDC.Authorizer;
using HCD.Web.MDC.Hubs;
using Hangfire;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Partner.Utility.WeChat;
using System.Reflection;
using System.Linq;
using Microsoft.OpenApi.Models;
using System.Globalization;
using Microsoft.AspNetCore.Localization;
using Hangfire.Redis;
using Microsoft.Extensions.Hosting;

namespace HCD.Web.MDC.Startup
{
    /// <summary>
    /// 启动配置
    /// </summary>
    public class Startup
    {

        private readonly IConfiguration Configuration;

        //public IWeatherInfoAppService weatherInfoAppService { get; set; }
        /// <summary>
        /// Startup
        /// </summary>
        /// <param name="env"></param>
        public Startup(IWebHostEnvironment env)
        {
            var builder = new ConfigurationBuilder()
             .SetBasePath(env.ContentRootPath)
             .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
             .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
             .AddEnvironmentVariables();
            Configuration = builder.Build();
            JWTUtil.key = Configuration["Customization:JwtKey"];
        }

        /// <summary>
        /// ConfigureServices
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            //services.AddHangfire(r => r.UseSqlServerStorage(Configuration.GetConnectionString("Default")));

            services.AddSignalR();
            //services.AddSingleton<IServiceProvider, ServiceProvider>();

            services.AddControllersWithViews(options =>
            {
                //options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
                options.Filters.Add<IdempotenceFilter>();
                options.Filters.Add(typeof(AuthorFilter)); //身份过滤器
                options.Filters.Add(typeof(ExceptionResultFilter)); //异常过滤器
            })
            .AddDataAnnotationsLocalization(options =>
            {
                options.DataAnnotationLocalizerProvider = (type, factory) =>
                    factory.Create(typeof(HCD.Resources.Localization.Resx.Lang));
            })
            .AddNewtonsoftJson(options =>
            {
                //驼峰序列化方式：命名前几个字母连续大写，驼峰序列化方式 会把连续的大写全部变成小写，直到遇到小写字母和一些分隔字符
                //所以最优的方式首字母小写；如果非要首字母大写，第二个字母请小写
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss:fff";
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            })
            .AddXmlSerializerFormatters();

            services.Configure<RequestLocalizationOptions>(options =>
            {
                var supportedCultures = new[] { new CultureInfo("zh"), new CultureInfo("en") };

                options.DefaultRequestCulture = new RequestCulture(culture: "zh", uiCulture: "zh");
                options.SupportedCultures = supportedCultures;
                options.SupportedUICultures = supportedCultures;
            });
            //允许跨域
            services.AddCors();
            //services.AddHostedService<PushService>();
#if DEBUG
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new OpenApiInfo
                {
                    Version = "v1",
                    Title = "HCD API"
                });
                options.OperationFilter<ApiHeaderToken>();
                //options.DocumentFilter<ApplyDocumentVendorExtensions>();
                var currentAssembly = Assembly.GetExecutingAssembly();
                var xmlDocs = currentAssembly.GetReferencedAssemblies()
                .Union(new AssemblyName[] { currentAssembly.GetName() })
                .Select(a => Path.Combine(Path.GetDirectoryName(currentAssembly.Location), $"{a.Name}.xml"))
                .Where(f => File.Exists(f)).ToArray();
                Array.ForEach(xmlDocs, (d) =>
                {
                    options.IncludeXmlComments(d);
                });
            });
#endif
            //services.PostConfigure<MvcJsonOptions>(options =>
            //{
            //    //驼峰序列化方式：命名前几个字母连续大写，驼峰序列化方式 会把连续的大写全部变成小写，直到遇到小写字母和一些分隔字符
            //    //所以最优的方式首字母小写；如果非要首字母大写，第二个字母请小写
            //    options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            //    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
            //    options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
            //    options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            //});

            services.Configure<RazorViewEngineOptions>(options =>
            {

            });

            services.AddSingleton(Configuration);

            services.Configure<IISOptions>(options =>
            {
                options.ForwardClientCertificate = false;
            });

            services.AddHangfire(r => r.UseRedisStorage(
                Configuration.GetValue<string>("RedisMDC:ConnectionStrings"),
                new RedisStorageOptions()
                {
                    Db = Configuration.GetValue<int>("RedisMDC:DatabaseId"),
                    //其它配置这里定义
                }
            ));
            //Configure Abp and Dependency Injection
            return services.AddAbp<EnterpriseWebModule>(options =>
            {
                //Configure Log4Net logging
                options.IocManager.IocContainer.AddFacility<LoggingFacility>(
                    f => f.UseAbpLog4Net().WithConfig("log4net.config")
                );
            });

        }

        /// <summary>
        /// Configure
        /// </summary>
        /// <param name="app"></param>
        /// <param name="env"></param>
        /// <param name="loggerFactory"></param>
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            app.UseAbp();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Error/Index");
            }

            app.UseStaticFiles(new StaticFileOptions()
            {
                ContentTypeProvider = new FileExtensionContentTypeProvider()
                {
                    Mappings =
                    {
                        [".exe"] = "application/octect-stream" ,
                        [".manifest"] = "application/x-ms-manifest",
                        [".application"] = "application/x-ms-application",
                        [ ".apk"]= "application/vnd.android.package-archive"
                    }
                }
            });
            app.UseCors(c => c.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
#if DEBUG
            app.UseSwagger();
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "ABP.Core API V1");
            });
#endif
            app.UseWebSockets();
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapHub<SystemHub>("/systemHub");
                endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
            });

            //启动hangfire面板
            app.UseHangfireDashboard("/hangfire",
                new DashboardOptions()
                {
                    Authorization = new[] { new HangFireAuthorizeFilter() }
                });
            //启动Hangfire服务
            app.UseHangfireServer(
                new BackgroundJobServerOptions
                {
                    Queues = Configuration.GetValue<string>("RedisMDC:Queues").Split(','),//队列名称，只能为小写
                    WorkerCount = Environment.ProcessorCount * 5, //并发任务数 cpu 5倍，可以调高
                    ServerName = "hangfire_mdc",//服务器名称                     
                });
            //定时任务 Corn表达式定义时间规则 秒 分钟 小时 日期 月份 星期 年(可选)
            RecurringJob.AddOrUpdate<BackgroundWork.ProjectWorker>("TestJob", d => d.TestJob(),
                "*/15 * * * * *");//15秒 为最小执行单位
            RecurringJob.AddOrUpdate<BackgroundWork.ProjectWorker>("TestJob2", d => d.TestJob2(),
                "0 */1 * * * *");//1分钟
        }
    }
}